/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.admin.addins;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.ListChoice;
import org.apache.wicket.markup.html.form.PasswordTextField;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.Model;
import org.gidoo.cms.GidooCMS;
import org.gidoo.cms.admin.AdminPage;
import org.gidoo.cms.data.CMSSection;
import org.gidoo.cms.data.RegisteredUser;
import org.gidoo.cms.dbconnection.DatabaseConnectionException;
import org.gidoo.cms.dbconnection.Persistance;
import org.gidoo.cms.helper.Crypto;

/**
 * A panel where you can adminstrate a certain user.
 * @author Thomas
 */
public class SingleUserPanel extends AddInPanel
{
  
  private RegisteredUser theUser;
  
  private Form formDelete;
  private Form formPublish;
  private Form formEdit;
  private Form formChange;
  
  private Button btDelete;
  
  private ListChoice listPublishAllowed;
  private ListChoice listOtherSectionsPublish;
  private AjaxButton btPublish;
  private AjaxButton btDePublish;
  
  private ListChoice listEditAllowed;
  private ListChoice listOtherSectionsEdit;
  private AjaxButton btEdit;
  private AjaxButton btDeEdit;
  
  private TextField txtRealName;
  private TextField txtEMail;
  private PasswordTextField txtPassword1;
  private PasswordTextField txtPassword2;
  private CheckBox cbIsAdmin;
  private Button btChange;
  
  private AdminPage theParent;
  
  /**
   * Creates a new instance of UsersPanel.
   *
   * @param id The wicket id.
   * @param userID The id (username) of the user.
   */
  public SingleUserPanel(String id, RegisteredUser user, AdminPage parent)
  {
    super(id);
    this.theUser = user;
    this.theParent = parent;
    
    lblTitle.setModelObject((String) lblTitle.getModelObject() + theUser.getLoginName() );
    
    formDelete = new Form("formDelete");
    btDelete = new Button("btDelete", new Model(getString("deleteUser")))
    {
      @Override
      public void onSubmit()
      { 
        try
        {
          List<CMSSection> sections = ((GidooCMS) getApplication()).getDb().getAllSections();
          
          for(CMSSection s : sections)
          {
            if(s.getEditors().remove(theUser) ||
               s.getPublishers().remove(theUser))
            {
              s = (CMSSection) ((GidooCMS) getApplication()).getDb().merge(s);
            }
          }
          
          ((GidooCMS) getApplication()).getDb().remove(theUser);
          theParent.setSelectedNode(null);
          theParent.updateDataAndView();
        }
        catch(DatabaseConnectionException ex)
        {
          Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
          error(ex.getMessage());
        }
      }
    };
    
    formDelete.add(btDelete);
    
    
    formPublish = new Form("formPublish");
    formEdit = new Form("formEdit");
    
    listOtherSectionsPublish = new ListChoice("listOtherSectionsPublish");
    listPublishAllowed = new ListChoice("listPublishAllowed");
    listOtherSectionsEdit = new ListChoice("listOtherSectionsEdit");
    listEditAllowed = new ListChoice("listEditAllowed");
    
    listOtherSectionsPublish.setMaxRows(5);
    listOtherSectionsPublish.setNullValid(true);
    listOtherSectionsPublish.setRequired(false);
    listOtherSectionsPublish.setOutputMarkupId(true);
    
    listPublishAllowed.setMaxRows(5);
    listPublishAllowed.setNullValid(true);
    listPublishAllowed.setRequired(false);
    listPublishAllowed.setOutputMarkupId(true);
    
    listOtherSectionsEdit.setMaxRows(5);
    listOtherSectionsEdit.setNullValid(true);
    listOtherSectionsEdit.setRequired(false);
    listOtherSectionsEdit.setOutputMarkupId(true);
    
    listEditAllowed.setMaxRows(5);
    listEditAllowed.setNullValid(true);
    listEditAllowed.setRequired(false);
    listEditAllowed.setOutputMarkupId(true);
    
    formPublish.add(listOtherSectionsPublish);
    formPublish.add(listPublishAllowed);
    formEdit.add(listEditAllowed);
    formEdit.add(listOtherSectionsEdit);
    
    listOtherSectionsPublish.setModel(new Model(new String()));
    listPublishAllowed.setModel(new Model(new String()));
    listOtherSectionsEdit.setModel(new Model(new String()));
    listEditAllowed.setModel(new Model(new String()));
    
    btPublish = new AjaxButton("btPublish") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        addPublish();
        target.addComponent(feedback);
        target.addComponent(listPublishAllowed);
        target.addComponent(listOtherSectionsPublish);
      }
    };
    btPublish.setModel(new Model(getString("add")));
    
    btDePublish = new AjaxButton("btDePublish") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        deletePublish();
        target.addComponent(feedback);
        target.addComponent(listPublishAllowed);
        target.addComponent(listOtherSectionsPublish);
      }
    };
    btDePublish.setModel(new Model(getString("delete")));
    
    formPublish.add(btPublish);
    formPublish.add(btDePublish);
    
    btEdit = new AjaxButton("btEdit") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        addEdit();        
        target.addComponent(feedback);
        target.addComponent(listEditAllowed);
        target.addComponent(listOtherSectionsEdit);
      }
    };
    btEdit.setModel(new Model(getString("add")));
    
    btDeEdit = new AjaxButton("btDeEdit") {

      @Override
      protected void onSubmit(AjaxRequestTarget target, Form form)
      {
        deleteEdit();
        target.addComponent(feedback);
        target.addComponent(listEditAllowed);
        target.addComponent(listOtherSectionsEdit);
      }
    };
    btDeEdit.setModel(new Model(getString("delete")));
    
    formEdit.add(btEdit);
    formEdit.add(btDeEdit);
    
    formChange = new Form("formChange");
    
    txtRealName = new TextField("txtRealName", new Model(""));
    txtEMail = new TextField("txtEMail", new Model(""));
    txtPassword1 = new PasswordTextField("txtPassword1", new Model(""));
    txtPassword2 = new PasswordTextField("txtPassword2", new Model(""));
    txtPassword1.setRequired(false);
    txtPassword2.setRequired(false);
      
    cbIsAdmin = new CheckBox("cbIsAdmin", new Model(new Boolean(false)));
    
    btChange = new Button("btChange", new Model(getString("change")))
    {
      @Override
      public void onSubmit()
      {
        changeUserInfo();
      }
      
    };
    
    formChange.add(txtRealName);
    formChange.add(txtEMail);
    formChange.add(txtPassword1);
    formChange.add(txtPassword2);
    formChange.add(cbIsAdmin);
    formChange.add(btChange);
    
    add(formPublish);
    add(formEdit);
    add(formDelete);
    add(formChange);
    
    updateDataAndView(theUser);
    
  }
  
  private void changeUserInfo()
  {
    try
    {
      theUser.setFullName(txtRealName.getModelObjectAsString());
      theUser.setEmail(txtEMail.getModelObjectAsString());
      Boolean b = (Boolean) cbIsAdmin.getModelObject();
      theUser.setIsAdmin(b.booleanValue());

      boolean changedpwd = false;
      String pwd1 = txtPassword1.getModelObjectAsString();
      if(pwd1 != null && !"".equals(pwd1))
      {
        if(!pwd1.equals(txtPassword2.getModelObjectAsString()))
        {
          error(getString("passwordsnotequal"));
        }
        else
        {
          try
          {
            theUser.setPasswordHash(Crypto.calculateSHAHash(pwd1));
            changedpwd = true;
          }
          catch(Exception ex)
          {
            Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
            error(getString("cryptoerror"));
          }          
        }
      }
      
      theUser = (RegisteredUser) ((GidooCMS) getApplication()).getDb().merge(theUser);
      if(changedpwd)
      {
        info(getString("changeduserinfoandpwd"));
      }
      else
      {
        info(getString("changeduserinfo"));
      }
      
    }
    catch (DatabaseConnectionException ex)
    {
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("dberror"));
    }
    
    updateDataAndView(theUser);
  }
  
  private void addPublish()
  {
    try
    {
      if("".equals(listOtherSectionsPublish.getModelObjectAsString()))
      {
        return;
      }
      
      CMSSection section = 
        ((GidooCMS) getApplication()).getDb().getSectionByExactUrl(listOtherSectionsPublish.getModelObjectAsString());
      
      if(!section.getPublishers().add(theUser) ||
         !theUser.getSections_publish().add(section))
      {
        error(getString("error"));
      }
      else
      {
        section = (CMSSection) ((GidooCMS) getApplication()).getDb().merge(section);
        theUser = (RegisteredUser) ((GidooCMS) getApplication()).getDb().merge(theUser);
        updateLists();
      }
      
    } catch (DatabaseConnectionException ex)
    {
      error(getString("dberror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
  private void addEdit()
  {
    try
    {
      if("".equals(listOtherSectionsEdit.getModelObjectAsString()))
      {
        return;
      }
      
      CMSSection section = 
        ((GidooCMS) getApplication()).getDb().getSectionByExactUrl(listOtherSectionsEdit.getModelObjectAsString());
      
      if(!section.getEditors().add(theUser) ||
         !theUser.getSections_edit().add(section))
      {
        error(getString("error"));
      }
      else
      {
        section = (CMSSection) ((GidooCMS) getApplication()).getDb().merge(section);
        theUser = (RegisteredUser) ((GidooCMS) getApplication()).getDb().merge(theUser);
        updateLists();
      }
      
    } 
    catch (DatabaseConnectionException ex)
    {
      error(getString("dberror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }    
  }
  
  private void deletePublish()
  {
    try
    {
      if("".equals(listPublishAllowed.getModelObjectAsString()))
      {
        return;
      }
            
      CMSSection section =
        ((GidooCMS) getApplication()).getDb().getSectionByExactUrl(listPublishAllowed.getModelObjectAsString());
      
      if(!section.getPublishers().remove(theUser) ||
         !theUser.getSections_publish().remove(section))
      {
        error(getString("error"));
      }
      else
      {   
        section = (CMSSection) ((GidooCMS) getApplication()).getDb().merge(section);
        theUser = (RegisteredUser) ((GidooCMS) getApplication()).getDb().merge(theUser);
        updateLists();
      }
      
    }
    catch (DatabaseConnectionException ex)
    {
      error(getString("dberror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
  private void deleteEdit()
  {
    try
    {
      if("".equals(listEditAllowed.getModelObjectAsString()))
      {
        return;
      }
      
      CMSSection section =
        ((GidooCMS) getApplication()).getDb().getSectionByExactUrl(listEditAllowed.getModelObjectAsString());
      
      if(!section.getEditors().remove(theUser) ||
         !theUser.getSections_edit().remove(section))
      {
        error(getString("error"));
      }
      else
      {        
        
        section = (CMSSection) ((GidooCMS) getApplication()).getDb().merge(section);
        theUser = (RegisteredUser) ((GidooCMS) getApplication()).getDb().merge(theUser);
        
        updateLists();
      }
    }
    catch (DatabaseConnectionException ex)
    {
      error(getString("dberror"));
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
  private void updateLists()
  {
    List<CMSSection> tmp = getSectionsNoPublish();
    listOtherSectionsPublish.setChoices(tmp);
    
    tmp = getSectionsPublish();
    listPublishAllowed.setChoices(tmp);
    
    tmp = getSectionsNoEdit();
    listOtherSectionsEdit.setChoices(tmp);
    
    tmp = getSectionsEdit();
    listEditAllowed.setChoices(tmp);
    
    
  }
  
  private List<CMSSection> getSectionsPublish()
  {    
    List<CMSSection> tmp = new LinkedList<CMSSection>(
            theUser.getSections_publish());
    Collections.sort(tmp);
    return tmp;

  }
  
  private List<CMSSection> getSectionsNoPublish()
  {
    try
    {
      List<CMSSection> tmp = new LinkedList<CMSSection>(((GidooCMS) getApplication()).getDb().getAllSections());
      
      
      tmp.removeAll(theUser.getSections_publish());
      
      Collections.sort(tmp);
      
      return tmp;
    } catch (DatabaseConnectionException ex)
    {
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("dberror"));
    }
    
    
    return new LinkedList<CMSSection>();
  }
  
  private List<CMSSection> getSectionsEdit()
  {    
    
    List<CMSSection> tmp = new LinkedList<CMSSection>(
        theUser.getSections_edit());
    Collections.sort(tmp);
    return tmp;
    
  }
  
  private List<CMSSection> getSectionsNoEdit()
  {
    try
    {
      List<CMSSection> tmp = new LinkedList<CMSSection>(((GidooCMS) getApplication()).getDb().getAllSections());
      
      tmp.removeAll(theUser.getSections_edit());
      
      Collections.sort(tmp);
      
      return tmp;
    } catch (DatabaseConnectionException ex)
    {
      Logger.getLogger(SingleUserPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("dberror"));
    }
    
    return new LinkedList<CMSSection>();
  }
  
  public void updateDataAndView(RegisteredUser user)
  {
    this.theUser = user;
    updateLists();
    
    txtRealName.setModelObject(theUser.getFullName());
    txtEMail.setModelObject(theUser.getEmail());
    cbIsAdmin.setModelObject(new Boolean(theUser.getIsAdmin()));
  }
}